package cn.jasonone.jame.model;

import cn.jasonone.jame.basic.*;
import cn.jasonone.jame.cycle.SpiritLifeCycle;
import cn.jasonone.jame.GameScene;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.image.Image;
import javafx.scene.paint.Color;
import javafx.scene.text.Font;
import javafx.util.Duration;
import lombok.*;

import java.util.Objects;

/**
 * 精灵对象
 *
 * @author Jason
 */
@Data
@ToString(exclude = {"gameContext","scene","animation"},callSuper = true)
@EqualsAndHashCode(exclude = {"gameContext","scene"})
public class Spirit extends Rect implements Draw, SpiritLifeCycle, UniquelyIdentifies, KeyEventHandler, MouseEventHandler {
    /**
     * 精灵所在游戏场景
     */
    private GameScene scene;

    @Setter(AccessLevel.PROTECTED)
    @Getter(AccessLevel.PROTECTED)
    private Animation animation;
    /**
     * 得到当前所在层
     */
    private int floor;
    /**
     * 精灵的唯一标识符
     */
    private String id;
    /**
     * 颜色
     */
    @Getter
    private Color strokeColor = Color.WHITE;
    /**
     * 字体
     */
    private Font font;

    private final BooleanProperty visible = new SimpleBooleanProperty(true);

    private GameContext<Spirit> gameContext;
    /**
     * 水平速度
     */
    private int speedHorizontal=1;
    /**
     * 垂直速度
     */
    private int speedVertical=1;

    public Spirit(Image image) {
        this.animation = new Animation(Duration.millis(20), image);
        this.setSize(this.animation.getSize());
    }

    public Spirit() {
        this.animation = new Animation(Duration.millis(20), Color.WHITE);
        this.setSize(this.animation.getSize());
    }

    public Spirit(Color color) {
        this.animation = new Animation(Duration.millis(20), color);
        this.setSize(this.animation.getSize());
    }

    public Spirit(Dimension size, Image... images) {
        this(new Point(), size, images);
    }

    public Spirit(Dimension size, Color... colors) {
        this(new Point(), size, colors);
    }

    public Spirit(double x, double y, double width, double height, Image... images) {
        this(new Point(x, y), new Dimension(width, height), images);
    }

    public Spirit(double x, double y, double width, double height, Color... colors) {
        this(new Point(x, y), new Dimension(width, height), colors);
    }

    public Spirit(double x, double y, Image... images) {
        this(new Point(x, y), images);
        Image image = this.animation.getImage();
        this.setSize(image.getWidth(), image.getHeight());
    }

    public Spirit(double x, double y, Color... colors) {
        this(new Point(x, y), colors);
        Image image = this.animation.getImage();
        this.setSize(image.getWidth(), image.getHeight());
    }

    public Spirit(Point point, Image... images) {
        this(point, new Dimension(), images);
    }

    public Spirit(Point point, Color... colors) {
        this(point, new Dimension(), colors);
    }

    public Spirit(Point point, Dimension size, Image... images) {
        this(new Rect(point, size), images);
    }

    public Spirit(Point point, Dimension size, Color... colors) {
        this(new Rect(point, size), colors);
    }

    public Spirit(Rect rect, Image... images) {
        this(rect, Duration.millis(20), images);
    }

    public Spirit(Rect rect, Color... colors) {
        this(rect, Duration.millis(20), colors);
    }

    public Spirit(Rect rect, Duration duration, Image... images) {
        this(new Animation(duration, images), rect);
    }

    public Spirit(Rect rect, Duration duration, Color... colors) {
        this(new Animation(duration, colors), rect);
    }

    public Spirit(Animation animation, Rect rect) {
        this.animation = animation;
        this.setRect(rect);
    }

    public void setSpeed(int speed){
        this.setSpeedHorizontal(speed);
        this.setSpeedVertical(speed);
    }

    @Override
    public void draw(GraphicsContext gc) {
        if (this.animation.getImage() != null) {
            gc.drawImage(this.animation.getImage(), this.getX(), this.getY(), this.getWidth(), this.getHeight());
        } else if (this.animation.getColor() != null) {
            gc.setFill(this.animation.getColor());
        }
    }

    @Override
    public void update() {

    }

    @Override
    public void visible(GameContext<GameScene> gc, boolean visible) {
        if (visible) {
            this.animation.play();
        } else {
            this.animation.pause();
        }
    }

    public boolean isVisible() {
        return this.visible.get();
    }

    public void setVisible(boolean visible) {
        this.visible.set(visible);
    }

    /**
     * 得到当前精灵所在显示层
     *
     * @return 层
     */
    @Override
    public int getFloor() {
        return this.floor;
    }

    @Override
    public void setId(String id) {
        Objects.requireNonNull(id, "ID不能为null");
        this.id = id;
    }

    @Override
    public String getId() {
        if (this.id == null) {
            setId(createId());
        }
        return this.id;
    }

    public Color getFillColor() {
        return this.animation.getColor();
    }

    public void setFillColor(Color color) {
        this.animation.setColor(color);
    }

    @Override
    public Rect getRect() {
        return this;
    }

    public void remove() {
        if (this.scene != null) {
            this.scene.remove(this);
        }
    }

    @Override
    public void init(GameContext<GameScene> gc) {
        gameContext=new DefaultGameContext<>(this,gc);
    }

    public void moveTop(){
        this.move(0,-this.speedVertical);
    }

    public void moveBottom(){
        this.move(0,this.speedVertical);
    }

    public void moveLeft(){
        this.move(-this.speedHorizontal,0);
    }
    public void moveRight(){
        this.move(this.speedHorizontal,0);
    }
}
